主要内容:
- 对象比较(使用 equals 方法比较两个对象内容是否相同,使用 compareTo 方法比较两个对象的大小。)
- 对象组合(描述对象之间的关系:包含或者引用。)
- 对象复制(把一个对象的内容全部复制到另一个对象里面。)
对象比较
Comparable 接口
Comparable 接口里面定义了一个 compareTo 方法,这个方法接收一个对象。
Comparable 接口定义如下:
1 | public interface Comparable<T> { |
通常一个类实现 Comparable 接口,然后在 CompareTo 方法中对两个对象(一个是形参,一个是 this)进行比较。如果 this 比较小,则返回 -1,相等则返回 0,否则返回 1 。
下面定义了一个学生类,它实现了 Comparable 接口,在 compareTo 方法中,通过分数比较两个对象的大小。
1 | class Student implements Comparable<Student>{ // 需要指明泛型接口的类型变量,不能使用 T |
实现了 Comparable 接口,并且写好了 compareTo 方法,所以两个学生对象之间就可以比较大小了。
我们可以利用 compareTo 方法,自定义方法来比较两个对象的大小,也可以利用 JDK 自带的方法对学生数组进行排序。如下:
1 | public class StudentSort { |
equals 方法
- 如果使用 ”==“ 比较两个对象,那么比较的是这两个对象变量是否引用同一个对象。
- 如果需要比较对象的内容,也就是各字段的值,通常是调用对象的 equals 方法。
- equals 方法由 Object 类所定义,默认情况下还是比较两个对象变量是否引用同一个对象。所以通常需要重写 equals 方法。
1 | public boolean equals(Object obj) { |
- 重写 Object 的 equals 方法,注意其参数类型必须是 ”Object“。
- 重写 Object 的模板:
1 | // 重写 equals 的模板 |
自定义比较规则
之前说过,实现了 Comparable 接口,就可以调用 Arrays.sort() 进行排序,它默认从小到大进行排序。
假设对学生排序,而学生类的 compareTo 方法是根据分数返回 0、-1 或者 1 。那么默认是根据分数从小到达进行排序。
如果想根据学生的姓名进行排序该怎么办呢?方法是自定义比较规则。
- 自定义一个类,实现 Comparator 接口
- 重写 compare 方法(接收两个对象,返回 0、-1 或 1 ,表示 s1 和 s2 比较的结果)
- 在调用 Arrays.sort() 的时候,将自定义比较规则传入
1 | class NameComparator implements Comparator<Student> { |
1 | Arrays.sort(students2, new NameComparator()); |
这样一来,学生对象的数组就已经根据名字来排序了。
对象组合
一个对象包容另一个对象,称为“对象组合”。
有两种组合方式:
- A 对象完全包容 B 对象,容器对象管理被包容对象的生命期。(B 是 A 的内部类)
- B 对象是独立的,A 对象引用现成的 B 对象。(A 对象里面有一个 B 的引用而已)
对象复制
- 浅克隆,只是复制每个字段的值
1 | public class CloneATest { |
- 如果类中 b 字段引用一个对象,那么浅克隆的方式可能会导致,两个对象的 b 字段指向同一个对象,这显然不是真正的复制,我们需要的是两个对象的 b 各自指向一个对象,同时被指向的对象的内容完全一样。而这就是深克隆。
1 | public class DeepCopy { |
- JDK 中提供了一个 Cloneable 接口,需要深克隆的对象可以实现这一接口。(注意强制类型转换和捕获异常)
1 | public class DeepCopy2 { |